package com.alibaba.cola.statemachine.impl;

import com.alibaba.cola.statemachine.Transition;
import com.alibaba.cola.statemachine.exception.StateMachineException;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * EventTransitions
 * <p>
 * <a href="https://github.com/alibaba/COLA/pull/158">同一个Event可以触发多个Transitions，</a>
 *
 * @author Frank Zhang
 * @date 2021-05-28 5:17 PM
 */
public class EventTransitions<S, E, C> {
    private final Map<E, List<Transition<S, E, C>>> eventTransitions = new HashMap<>();

    public void put(E event, Transition<S, E, C> transition) {
        var transitions = eventTransitions.get(event);
        if (transitions == null) {
            transitions = new ArrayList<>();
            transitions.add(transition);
            eventTransitions.put(event, transitions);
        } else {
            verify(transitions, transition);
            transitions.add(transition);
        }
    }

    /**
     * Per one source and target state, there is only one transition is allowed
     * 每一个原状态和目标状态，只允许有一个流转
     *
     * @param existingTransitions 当前流转集合
     * @param newTransition       新的流转
     */
    private void verify(List<Transition<S, E, C>> existingTransitions, Transition<S, E, C> newTransition) {
        for (Transition<S, E, C> transition : existingTransitions) {
            if (transition.equals(newTransition)) {
                throw new StateMachineException(transition + " already Exist, you can not add another one");
            }
        }
    }

    /**
     * Get all transitions for the event
     * 获取某个事件的所有流转
     *
     * @param event 事件
     * @return 流转集合
     */
    public List<Transition<S, E, C>> get(E event) {
        return eventTransitions.get(event);
    }

    /**
     * Get all transitions
     * 获取所有流转
     * @return 流转集合
     */
    public List<Transition<S, E, C>> allTransitions() {
        List<Transition<S, E, C>> allTransitions = new ArrayList<>();
        for (List<Transition<S, E, C>> transitions : eventTransitions.values()) {
            allTransitions.addAll(transitions);
        }
        return allTransitions;
    }
}
